home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / jf90 / MidiIX-33.ascii < prev    next >
Encoding:
Text File  |  1990-03-26  |  8.1 KB  |  171 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either express or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8. MIDI Output in Assembler
  9.  
  10. by Darius Taghavy, CATS
  11.  
  12.  
  13. The Amiga's serial.device provides a software interface to the serial port 
  14. which is suitable for a wide variety of purposes.  However, high-performance 
  15. applications such as MIDI drivers may require direct access to the Amiga 
  16. hardware which controls the serial port.  The program listed below shows how 
  17. to send MIDI data over the serial port using direct access to the Amiga's 
  18. Paula chip I/O registers.
  19.  
  20. It is important to note that MIDI applications which use direct access to 
  21. the serial port I/O registers must first gain exclusive access to the serial 
  22. hardware by opening the misc.resource and allocating MR_SERIALBITS and 
  23. MR_SERIALPORT.  By doing this, the application becomes the "owner" of the 
  24. serial port which prevents other tasks which may be running from interfering 
  25. with serial I/O.
  26.  
  27. The example program demonstrates direct access to the internal serial port 
  28. through the Paula chip I/O registers and provides a very useful MIDI function:
  29. it turns off all notes.  If you have ever used MIDI software, then you may 
  30. be familiar with the stuck-note phenomenon.  A stuck note is a note that 
  31. sustains forever.  Stuck notes happen because the duration of a note is 
  32. determined by the elapsed time between a NOTE ON and a NOTE OFF event.  If 
  33. a NOTE OFF event ever gets lost you end up with a stuck note.  The MIDI 
  34. standard does provide an ALL NOTES OFF command, however, not all tone 
  35. generators respond to it properly, and not all sequencers provide a way to 
  36. send the command.
  37.  
  38. The example program, named Panic, solves this problem by sending a NOTE ON
  39. command with a velocity of zero for all 128 notes on all 16 channels.  In 
  40. other words, each possible note is turned of individually forcing the 
  41. sustaining culprit in your MIDI system to shut up.
  42.  
  43. The Panic program is written in assembler to keep the code small and to save 
  44. execution time.  The program also employs the idea of a running status to 
  45. save execution time by reducing the number of bytes it has to send.  In 
  46. accordance with the official MIDI specification, as long as data of the same 
  47. status is being sent (i.e., NOTE ON) we can just keep sending the associated 
  48. data bytes which, in this case, is 2 bytes for pitch and velocity, 
  49. respectively.  There is no need to re-transmit the status byte with every 
  50. message.
  51.  
  52. In the example code, this is implemented by cycling through the (inner) 
  53. note_loop for 128 times, once for each MIDI note number.  Since the MIDI 
  54. channel information is imbedded in the lower nybble of the status byte, a 
  55. new status byte must be sent when switching to a different channel. This is 
  56. implemented as the (outer) channel_loop which loops 16 times, once for each 
  57. MIDI channel.  Using a running status cuts I/O activity by a third.
  58.  
  59. Panic demonstrates assembler independent code by using the SECTION CODE
  60. and SECTION DATA directives. All Amiga assemblers will understand this. Panic 
  61. also uses the statement, XDEF _panic, to make it callable from another module 
  62. (say, a C main program).  Manx users, please note that this is much better 
  63. than using the Manx directive public since it is portable between assemblers 
  64. (public is not).  Use XREF for referencing external labels and XDEF for 
  65. making labels available to external modules. 
  66.  
  67. Panic can be assembled and linked as is. No special assembler or linker flags 
  68. are needed.  The resulting executable is a mere 164 bytes long and only takes 
  69. approximately 1.3 seconds to execute (using MANX 3.6a as and ln).
  70. The length of the transmitted MIDI data itself is 4112 bytes: 
  71.  
  72. (2 note/velocity bytes * 128 notes) + (1 status byte * 16 channels) 
  73. = 4112 bytes. 
  74.  
  75. The MIDI transfer rate is defined as 31250 baud or about 3125 MIDI bytes/sec. 
  76. This figure takes into account start and stop bits ( a MIDI byte is 10 bits ).
  77. Hence, time t for transmitting these events in an ideal world (ideal UART and 
  78. crystal) is: 
  79.        
  80.     total number of bytes        4112 bytes
  81. t = ---------------------------- = --------------------- = 1.31584 seconds.
  82.     MIDI transfer rate        3125 bytes/sec
  83.  
  84. Note that the Panic program assumes the serial baud rate is already set to 
  85. 31250 baud and that the misc.resource has been allocated.  As such there are 
  86. two uses for this program.
  87.  
  88. First, Panic could be used as a utility in conjunction with a sequencer that 
  89. does not have a true all-notes-off feature or that lacks even the generic 
  90. MIDI command \ff<Courier>ALL NOTES OFF\ff<Times>.  In fact, I originally 
  91. wrote Panic because no Amiga sequencer at the time offered this important 
  92. feature.  
  93.  
  94. When Panic is used this way, it makes sense to not set the serial baud rate 
  95. (your sequencer already took care of it) and to not allocate the serial port 
  96. (the sequencer probably already has exclusive access to it).
  97.  
  98. A second use for Panic would be to link it with your own code (say, a 
  99. sequencer) which properly allocates the serial port and sets the baud rate.  
  100. I encourage developers to include Panic in their code.  In either case, it 
  101. is important to make sure that other tasks have been locked out from using 
  102. the serial port before hitting the serial port hardware registers directly.
  103.  
  104. The program is listed on the next page.
  105.  
  106.  
  107. ;---------------------------------------------------------------- 
  108. ; PANIC (c)1990 by Darius Taghavy
  109. ;---------------------------------------------------------------- 
  110. ;sends note #0-127 with zero (0) velocity on all 16 MIDI channels 
  111. ;MANX: as panic.asm; ln panic panic.o 
  112. ;---------------------------------------------------------------- 
  113. ; this code assumes SERPER register to be set to MIDI baud rate
  114. ; it also assumes that we have exclusive access to the serial port
  115. ; hardware and related resources
  116.  
  117.  
  118.                     SECTION CODE
  119. XDEF               _panic                ;make available as 'C' function
  120.  
  121.                     SECTION DATA
  122. CUSTOM_CHIPS     equ           $dff000   ;custom chips base address
  123. TBE              equ           5         ;Transmitt Buffer Empty Bit
  124.  
  125. ;Paula serial port register offsets from custom chip base address
  126. SERDAT           equ           $030      ;data output(WRITE ONLY)
  127. SERDATR          equ           $018      ;data/status(READ ONLY)
  128.  
  129.  
  130.                     SECTION CODE
  131. _panic              move.l        d2,-(a7)             ;save d2
  132.                     lea           CUSTOM_CHIPS,a0      ;load custom chip base
  133.                     move.w        #15,d1               ;16 MIDI channels
  134. channel_loop        move.w        #127,d2              ;128 MIDI notes
  135.  
  136. ;-------------status byte
  137.                     move.b        d1,d0                ;get MIDI channel
  138.                     andi.b        #$f,d0               ;nibble
  139.                     or.b          #$90,d0              ;Note On Status
  140.                     andi.w        #$ff,d0              ;clear high byte
  141.                     ori.w         #$100,d0             ;set stop bit
  142.  
  143. 1$                  btst.b        #TBE,SERDATR(a0)     ;wait for free serialport
  144.                     beq           1$
  145.  
  146.                     move.w        d0,SERDAT(a0)        ;send byte
  147.  
  148. ;-------------note number
  149.  
  150. note_loop           move.b        d2,d0                ;get note number
  151.                     andi.w        #$ff,d0              ;clear high byte
  152.                     ori.w         #$100,d0             ;set stop bit
  153.  
  154. 2$                  btst.b        #TBE,SERDATR(a0)     ;wait for free serialport
  155.                     beq           2$
  156.                     move.w        d0,SERDAT(a0)        ;send pitch byte
  157.  
  158. ;------------velocity = 0
  159.  
  160. 3$                  btst.b        #TBE,SERDATR(a0)     ;wait for free serialport
  161.                     beq           3$
  162.                     
  163.                     move.w        #$100,SERDAT(a0)     ;send zero velocity
  164.  
  165.                     dbra          d2,note_loop         ;loop 128 times
  166.                     dbra          d1,channel_loop      ;loop 16 times
  167.                     move.l        (a7)+,d2             ;restore d2
  168.                     rts
  169.  
  170.                     END
  171.